package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domin.po.PointsBoard;
import com.tianji.learning.domin.po.PointsBoardSeason;
import com.tianji.learning.domin.vo.PointsBoardItemVO;
import com.tianji.learning.domin.vo.PointsBoardVO;
import com.tianji.learning.mapper.PointsBoardMapper;
import com.tianji.learning.query.PointsBoardQuery;
import com.tianji.learning.service.IPointsBoardSeasonService;
import com.tianji.learning.service.IPointsBoardService;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 学霸天梯榜 服务实现类
 * </p>
 *
 * @author author
 * @since 2023-11-09
 */
@Service
@RequiredArgsConstructor
public class PointsBoardServiceImpl extends ServiceImpl<PointsBoardMapper, PointsBoard> implements IPointsBoardService {
    private final IPointsBoardSeasonService pointsBoardSeasonService;
    private final StringRedisTemplate redisTemplate;
    private final UserClient userClient;

    /**
     * 创建积分排行榜表
     *
     * @param tableName 表名
     */
    @Override
    public void createPointsBoardTable(String tableName) {
        getBaseMapper().createPointsBoardTable(tableName);
    }


    @Cacheable(value = "seasonsCache")
    @Override
    public List<PointsBoardSeason> findAllSeasons() {
        return pointsBoardSeasonService.list();
    }

    @Override
    public PointsBoardVO queryPointsBoardBySeason(PointsBoardQuery query) {

        //获取当前登录用户Id
        Long userId = UserContext.getUser();
        //判断 赛季id，为空或0时，代表查询当前赛季。否则就是查询历史赛季
        boolean isCurrent = query.getSeason() == 0 || query.getSeason() == null;

        //拼接key
        LocalDate now = LocalDate.now();
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX + now.format(DateUtils.POINTS_BOARD_SUFFIX_FORMATTER);
        //查询我的排行榜
        PointsBoard myBoard = isCurrent ? MyCurrentBoard(key) ://当前排行榜:
                MyHistoryBoard(key); //历史排行榜
        //查询redis封装PointsBoardItemVOs
        List<PointsBoard> pointsBoards = queryCurrentBoardList(key, query.getPageNo(), query.getPageSize());
        //封装Vo返回
        PointsBoardVO vo = new PointsBoardVO();

        if (myBoard != null) {
            vo.setRank(myBoard.getRank());
            vo.setPoints(myBoard.getPoints());
        }
        if (CollUtils.isEmpty(pointsBoards)) {
            return vo;
        }
        List<Long> userIds = pointsBoards.stream().map(PointsBoard::getUserId).collect(Collectors.toList());
        //查询用户信息
        List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
        Map<Long, UserDTO> userDTOMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, O -> O));

        List<PointsBoardItemVO> boardItemVOS = pointsBoards.stream().map(pointsBoard -> {
            PointsBoardItemVO pointsBoardItemVO = BeanUtils.copyBean(pointsBoard, PointsBoardItemVO.class);
            UserDTO userDTO = userDTOMap.get(pointsBoard.getUserId());
            pointsBoardItemVO.setName(userDTO.getName());
            return pointsBoardItemVO;
        }).collect(Collectors.toList());

        vo.setBoardList(boardItemVOS);
        return vo;
    }



    public List<PointsBoard> queryCurrentBoardList(String key, Integer pageNo, Integer pageSize) {
        int form = (pageNo - 1) * pageSize;

        Set<ZSetOperations.TypedTuple<String>> range = redisTemplate.opsForZSet().reverseRangeWithScores(key, form, form + pageSize - 1);
        ArrayList<PointsBoard> list = new ArrayList<>();
        PointsBoard p = new PointsBoard();
        list.add(p);
        if (CollUtils.isEmpty(range)) {
            return CollUtils.emptyList();
        }
        int rank = form + 1;
        for (ZSetOperations.TypedTuple<String> tuple : range) {
            Double points = tuple.getScore();
            String userId = tuple.getValue();
            if (points == null || userId == null) {
                continue;
            }
            p.setRank(rank++);
            p.setUserId(Long.parseLong(userId));
            p.setPoints(points.intValue());
        }

        return list;

    }

    private PointsBoard MyHistoryBoard(String key) {
        return null;
    }

    private PointsBoard MyCurrentBoard(String key) {
        BoundZSetOperations<String, String> ops = redisTemplate.boundZSetOps(key);
        String userId = UserContext.getUser().toString();
        Double points = ops.score(userId);
        Long rank = ops.reverseRank(userId);
        PointsBoard p = new PointsBoard();

        p.setPoints(points == null ? 0 : points.intValue());
        p.setRank(rank == null ? 0 : rank.intValue() + 1);
        return p;
    }

}
